package edu.spec.madfrog.util;


import android.serialport.SerialPort;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ZigbeeAPI {
	private static FileOutputStream fos;
	private static FileInputStream fis;
	private static SerialPort sp;
	private static byte[] buffer = new byte[64];
	private static ReadThread mreadthread;

	/**
	 * 初始化，这里定义要打开哪个串口。这里打开的串口是"/dev/ttySAC0"，不同的设备打开的串口不同，需注意修改
	 */
	static {
		try {
			sp = new SerialPort(new File("/dev/ttyAMA0"), 38400, 0);//串口和波特率
			mreadthread = new ReadThread();
			mreadthread.start();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * 发送
	 * @param cmd 要发送的数据
	 * @throws Exception
	 */
	private void PTsend(byte[] cmd) throws Exception {
		fos = (FileOutputStream) sp.getOutputStream();
		fos.write(cmd);
		fos.flush();
	}

	/** 
	 * 接收，单开一个线程来进行接收才有效果。
	 */
	private static class ReadThread extends Thread {
		@Override
		public void run() {
			super.run();
			fis = (FileInputStream) sp.getInputStream();
			while (!isInterrupted()) {
				int size;
				try {
					// byte[] buffer = new byte[64];			
					if (fis == null){}
					else{
					size = fis.read(buffer);
//					if(size>0)
//						return;
					}
				} catch (IOException e) {
					e.printStackTrace();
					return;
				}
			}
		}
	}



	/**
	 * 接收处理
	 * @param cmd
	 * @return byte[]，这里的byte数组长度取决于buffer数组的长度。内容取决于处理后需返回的数据
	 * @throws Exception
	 */
	private byte[] PTacceptDeal(byte[] cmd) throws Exception {
		
		cmd = buffer;
		int size = cmd.length;
		System.out.print(""+getClass()+":");
		for(int i=0;i<size;i++){
			System.out.print((byte)cmd[i]+"  ");
		}
		System.out.println();
		byte[] fanhui = null;
		//FC命令
		if (cmd[0] == (byte) 0xfc) {
			switch (cmd[1]) {
			case 0x12:
				fanhui = new byte[1];
				fanhui[0] = (byte) cmd[3];
				break;
			case 0x22:
				fanhui = new byte[2];
				fanhui[0] = (byte) cmd[3];
				fanhui[1] = (byte) cmd[4];
				break;
			case 0x32:
				fanhui = new byte[2];
				fanhui[0] = (byte) cmd[3];
				fanhui[1] = (byte) cmd[4];
				break;
			case 0x42:
				fanhui = new byte[1];
				fanhui[0] = (byte) cmd[3];
				break;
			case 0x52:
				fanhui = new byte[1];
				fanhui[0] = (byte) cmd[3];
				break;
			case 0x62:
				fanhui = new byte[8];
				fanhui[0] = (byte) cmd[3];
				fanhui[1] = (byte) cmd[4];
				fanhui[2] = (byte) cmd[5];
				fanhui[3] = (byte) cmd[6];
				fanhui[4] = (byte) cmd[7];
				fanhui[5] = (byte) cmd[8];
				fanhui[6] = (byte) cmd[9];
				fanhui[7] = (byte) cmd[10];
				break;
			case (byte)0xff:
				fanhui = new byte[1];
				fanhui[0] = (byte) 0xff;
			}
		}
		//FB命令
		else if (cmd[0] == (byte) 0xfb) {
			switch (cmd[4]) {
			case 0x02:
			case 0x06:
				fanhui = new byte[1];
				fanhui[0] = (byte) 0xff;
				break;
			case 0x52:
				fanhui = new byte[10];
				fanhui[0] = (byte) cmd[1];
				fanhui[1] = (byte) cmd[2];
				fanhui[2] = (byte) cmd[5];
				fanhui[3] = (byte) cmd[6];
				fanhui[4] = (byte) cmd[7];
				fanhui[5] = (byte) cmd[8];
				fanhui[6] = (byte) cmd[9];
				fanhui[7] = (byte) cmd[10];
				fanhui[8] = (byte) cmd[11];
				fanhui[9] = (byte) cmd[12];
			}
		}
		//FA命令
		else if (cmd[0] == (byte) 0xfa) {
			//待添加，由用户自行定义添加
			fanhui = new byte[1];
			fanhui[0] = (byte) 0xff;
		}
		return fanhui;
	}

	/**
	 * 获取设备类型
	 * @return byte数组，byte[0]表示当前设备的类型
	 * @throws Exception
	 */
	public byte[] zigbee_getStyle()throws Exception {
		// 串口返回来的值
		byte[] FCsend = { (byte) 0xfc, 0x10, 0x00, (byte) 0xf5 };
			PTsend(FCsend);
			delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
			return PTacceptDeal(buffer);
	}

	/**
	 * 设置设备类型
	 * @param  type 表示要设置的设备类型,取值为0（主设备，协调器）,1（路由）,2（节点，终端）
	 * @return	byte数组，byte[0]表示当前设备的类型
	 * @throws Exception
	 */
	public byte[] zigbee_setStyle(byte type) throws Exception {
		byte[] FCsend = { (byte) 0xfc, 0x11, 0x01, type, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
		
	}

	/**
	 * 获取网络号
	 * @return byte数组，byte[0]表示panl（网络号低8位），byte[1]表示panl（网络号高8位）
	 * @throws Exception
	 */
	public byte[] zigbee_getNetwork() throws Exception {
		byte[] FCsend = { (byte) 0xfc, 0x20, 0x00, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 * 设置网络ID
	 * @param panl 网络号低8位
	 * @param panh 网络号高8位
	 * @return byte数组，byte[0]表示panl（网络号低8位），byte[1]表示panl（网络号高8位）
	 * @throws Exception
	 */
	public byte[] zigbee_setNetwork(byte panl, byte panh) throws Exception {
		byte[] FCsend = { (byte) 0xfc, 0x21, 0x02, panl, panh, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 * 获取设备短地址
	 * @return byte数组，byte[0]表示addrl（短地址低8位），byte[1]表示addrh（短地址高8位）
	 * @throws Exception
	 */
	public byte[] zigbee_getAddr() throws Exception {
		byte[] FCsend = { (byte) 0xfc, 0x30, 0x00, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 * 获取通讯信道
	 * @return byte数组，byte[0]表示设备所处的当前chan（信道）
	 * @throws Exception
	 */
	public byte[] zigbee_getChannel() throws Exception {
		byte[] FCsend = { (byte) 0xfc, 0x40, 0x00, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 * 设置通讯信道
	 * @param chan 信道 范围0x00~0x0f,只有协调器可以设置
	 * @return byte数组，byte[0]表示设备所处的当前chan（信道）
	 * @throws Exception
	 */
	public byte[] zigbee_setChannel(byte chan) throws Exception {
		byte[] FCsend = { (byte) 0xfc, 0x41, 0x01, chan, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 * 获取终端节点数据轮询周期（pollrate）
	 * @return byte数组，byte[0]表示节点数据轮询周期
	 * @throws Exception
	 */
	public byte[] zigbee_getNodeCycle() throws Exception {
		byte[] FCsend = { (byte) 0xfc, 0x50, 0x00, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 * 设置终端节点数据轮询周期
	 * @param pollrate 表示终端节点数据轮询时间周期，一个字节，单位是100毫秒，范围是0x01~0x32，0x00表示不轮询。只有协调可以设置
	 * @return byte数组，byte[0]表示节点数据轮询周期
	 * @throws Exception
	 */
	public byte[] zigbee_setNodeCycle(byte pollrate) throws Exception {
		byte[] FCsend = { (byte) 0xfc, 0x51, 0x01, pollrate, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 * 获取本设备长地址（IEEE）IEEE[]----ieee地址
	 * @return byte[0]~byte[7]表示长地址（IEEE的地址，也叫MAC地址），每个模块的长地址出厂都是唯一的
	 * @throws Exception
	 */
	public byte[] zigbee_getIEEE() throws Exception {
		byte[] FCsend = { (byte) 0xfc, 0x60, 0x00, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 * 恢复出厂设置
	 * @return byte[0]==0xff，表示设置成功了
	 * @throws Exception
	 */
	public byte[] zigbee_FactoryReset() throws Exception {
		byte[] FCsend = { (byte) 0xfc, (byte) 0xf0, 0x00, (byte) 0xf5 };
		PTsend(FCsend);
		delay(2000);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	
	/**
	 *  设置入网许可
	 * @param prd 表示允许入网的时间周期，单位是秒，范围0x01~0xfe,0x00表示关闭允许，0xff表示打开允许。1字节，只有协调器可以设置
	 * @return byte[0]==0xff，表示设置成功了
	 * @throws Exception
	 */
	public byte[] zigbee_NetAllows(byte prd) throws Exception {
		byte[] FCsend = { (byte) 0xfc, (byte) 0xf1, 0x01, prd, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	// //设置网络秘钥 key[]----秘钥 16字节，只有协调器可设置
	// public void zigbee_NetKey(){
	//
	// }

	/**
	 *  重启设备
	 * @param addrl
	 * @param addrh
	 * @return byte[0]==0xff，表示设置成功了
	 * @throws Exception
	 */
	public byte[] zigbee_Restart(byte addrl, byte addrh) throws Exception {
		byte[] FCsend = { (byte) 0xfc, (byte) 0xf4, 0x00, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 *  设置节点重启
	 * @param addrl
	 * @param addrh
	 * @return byte[0]==0xff，表示设置成功了
	 * @throws Exception
	 */
	public byte[] zigbee_NodeFactoryReset(byte addrl, byte addrh) throws Exception {
		byte[] FCsend = { (byte) 0xfb, addrl, addrh, 0x01, 0x01, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	/**
	 *  设置节点恢复出厂设置
	 * @param addrl
	 * @param addrh
	 * @return byte[0]==0xff，表示设置成功了
	 * @throws Exception
	 */
	public byte[] zigbee_NodeRestart(byte addrl, byte addrh) throws Exception {
		byte[] FCsend = { (byte) 0xfb, addrl, addrh, 0x01, 0x05, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}
	/**
	 *  获取终端节点的IEEE地址
	 * @param addrl
	 * @param addrh
	 * @return byte[0]~byte[1] 表示终端短地址，byte[2]~byte[9]表示长地址（IEEE的地址，也叫MAC地址），每个模块的长地址出厂都是唯一的
	 * @throws Exception
	 */
	public byte[] zigbee_getNodeIEEE(byte addrl, byte addrh) throws Exception {
		byte[] FCsend = { (byte) 0xfb, addrl, addrh, 0x01, 0x50, (byte) 0xf5 };
		PTsend(FCsend);
		delay(20);//由于发送信息后，返回信息是有时间差的，如果不要延时，会直接报错
		return PTacceptDeal(buffer);
	}

	public FileOutputStream getFos(){
        fos = (FileOutputStream) sp.getOutputStream();
		return fos;
	}

	/**
	 * 当对象关闭时，关闭读写
	 */
	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		if (mreadthread != null)
			mreadthread.interrupt();
		fos.flush();
		fos.close();
		fis.close();
		sp = null;
		super.finalize();
		
	}
	/**
	 * 软件延时
	 * @param ms 延时多少毫秒
	 */
	private void delay(int ms){  
        try {  
            Thread.currentThread();  
            Thread.sleep(ms);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }   
     } 
}
